I'm learning JavaScript (again, and for real this time, I hope). After reading JavaScript: The Good Parts and several online pages, I set out to try some basic TDD in JavaScript. For these instructions (and the soon to be created instructional video), I'm using the following tool set:
Chrome (configured for auto updating)
Terminal (OS X Lion)
Java (to execute use the test runner)
Eclipse (to edit my files)
ViPlugin in Eclipse
This is my first stab at this and I hope to both get a better workflow and better at JavaScript.
% java -jar JsTestDriver-1.3.3d.jar --tests all
java.lang.IllegalArgumentException: The patterns/paths /Users/Thoughtworks/src
/workspaces/ RpnCalcDemo/src (/Users/Thoughtworks/src/workspaces/RpnCalcDemo/
src) used in the configuration file didn't match any file, the files patterns/
paths need to be relative /Users/Thoughtworks/src/workspaces/RpnCalcDemo
at com.google.jstestdriver.PathResolver.expandGlob(PathResolver.java:170)
at com.google.jstestdriver.PathResolver.resolve(PathResolver.java:109)
at com.google.jstestdriver.config.ParsedConfiguration.resolvePaths(
ParsedConfiguration.java:98)
at com.google.jstestdriver.config.Initializer.initialize(Initializer.java:84)
at com.google.jstestdriver.JsTestDriver.runConfigurationWithFlags(
JsTestDriver.java:259)
at com.google.jstestdriver.JsTestDriver.runConfiguration(
JsTestDriver.java:211)
at com.google.jstestdriver.JsTestDriver.main(JsTestDriver.java:144)
Unexpected Runner Condition: The patterns/paths /Users/Thoughtworks/src/
workspaces/RpnCalcDemo/src (/Users/Thoughtworks/src/workspaces/RpnCalcDemo/src)
used in the configuration file didn't match any file, the files patterns/
paths need to be relative /Users/Thoughtworks/src/workspaces/RpnCalcDemo
Use --runnerMode DEBUG for more information.
The system complains that the pattern "- src/*.js" does not match any files. So fix that:
src/rpn_calculator.js
var rpn_calculator =function(){var that ={};
that.x=function(){return0;};return that;};
Make a directory called logs and send (JUnit-formated XML-based) test output results there:
% mkdir logs
% java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs
.
Total 1 tests (Passed: 1; Fails: 0; Errors: 0) (1.00 ms)
Chrome 16.0.912.75 Mac OS: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (1.00 ms)
% ls logs
TEST-Chrome_16091275_Mac_OS.rpn_calculator.xml
% java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs
.E
Total 2 tests (Passed: 1; Fails: 0; Errors: 1) (0.00 ms)
Chrome 16.0.912.75 Mac OS: Run 2 tests (Passed: 1; Fails: 0; Errors 1) (0.00 ms)
rpn_calculator.testXShouldBeLastValueEntered error (0.00 ms): TypeError:
Object #<Object> has no method 'enter'
TypeError: Object #<Object> has no method 'enter'
at [object Object].testXShouldBeLastValueEntered (http://localhost:9876/test
/src-test/rpn_calculator_test.js:10:7)
Tests failed: Tests failed. See log for details.
Add the missing method (and update the implementation a touch):
src/rpn_calculator.js
var rpn_calculator =function(){var that ={};
that.value=0;
that.x=function(){return that.value;};
that.enter=function(value){
that.value= value;};return that;};
Run the tests, see the pass:
% java -jar JsTestDriver-1.3.3d.jar--tests all --testOutput logs
..
Total2 tests (Passed:2; Fails:0; Errors:0)(0.00 ms)
Chrome 16.0.912.75 Mac OS: Run 2 tests (Passed:2; Fails:0; Errors 0)(0.00 ms)
Refactor the rpn_calculator function, hide value:
var rpn_calculator =function(){var that ={};var value =0;
that.value=0;
that.x=function(){return value;};
that.enter=function(newValue){
value = newValue;};return that;};
Check, tests still pass?
% java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs
..
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (1.00 ms)
Chrome 16.0.912.75 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (1.00 ms)
Refactor the tests, remove duplication (this is multiple refactorings on my end):
This test will fail because there is no drop() method nor is this functionality supported.
% java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs
..E
Total 3 tests (Passed: 2; Fails: 0; Errors: 1) (0.00 ms)
Chrome 16.0.912.75 Mac OS: Run 3 tests (Passed: 2; Fails: 0; Errors 1) (0.00 ms)
rpn_calculator.testStoresMultipleValues error (0.00 ms): TypeError: Object #<Object>
has no method 'drop'
TypeError: Object #<Object> has no method 'drop'
at Object.testStoresMultipleValues (http://localhost:9876/test/src-test/
rpn_calculator_test.js:23:11)
Tests failed: Tests failed. See log for details.
After a little effort, we have this:
src/rpn_calculator.js
var rpn_calculator =function(){var that ={};var values =[0];
that.value= values;
that.x=function(){return values[values.length-1];;};
that.enter=function(newValue){
values.push(newValue);};
that.drop=function(){
values.pop()};return that;};
And the test are back to passing:
% java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs
...
Total 3 tests (Passed: 3; Fails: 0; Errors: 0) (1.00 ms)
Chrome 16.0.912.75 Mac OS: Run 3 tests (Passed: 3; Fails: 0; Errors 0) (1.00 ms)
One More Check
Notice the feature envy in the x function? I uses values the variable, the length of values and also has direct knowledge that the size is 0-based. This is not a huge deal, but there are defects in the system as written. Here's a test to demonstrate a problem:
java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs
...F
Total 4 tests (Passed: 3; Fails: 1; Errors: 0) (1.00 ms)
Chrome 16.0.912.75 Mac OS: Run 4 tests (Passed: 3; Fails: 1; Errors 0) (1.00 ms)
rpn_calculator.testCalculatorAlwaysHasValues failed (0.00 ms): AssertError: expected 0
but was [undefined]
AssertError: expected 0 but was [undefined]
at Object.testCalculatorAlwaysHasValues (http://localhost:9876/test/src-test/
rpn_calculator_test.js:30:2)
On both of my 2 HP calculators, I can drop all day long and nothing much happens (somewhat simplified, but reasonable for this demonstation. Conceptually, the so-called (by the documentation) "operand stack" is never empty. Here's a way to implement that:
% java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs
....E
Total 5 tests (Passed: 4; Fails: 0; Errors: 1) (1.00 ms)
Chrome 16.0.912.75 Mac OS: Run 5 tests (Passed: 4; Fails: 0; Errors 1) (1.00 ms)
rpn_stack.testPopOnNewStackReturns0 error (1.00 ms): ReferenceError: rpn_stack
is not defined
ReferenceError: rpn_stack is not defined
at [object Object].testPopOnNewStackReturns0 (http://localhost:9876/test/
src-test/rpn_stack_test.js:4:18)
Fix this by making one and giving it an implementation:
var rpn_stack =function(){
that ={};
that.pop=function(){return0;};return that;};
Now the tests pass:
% java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs
.....
Total 5 tests (Passed: 5; Fails: 0; Errors: 0) (1.00 ms)
Chrome 16.0.912.75 Mac OS: Run 5 tests (Passed: 5; Fails: 0; Errors 0) (1.00 ms)
Next, we want to make sure that the last value entered is the one that pop returns:
var rpn_stack =function(){
that ={};var values =[0];
that.pop=function(){return values.pop();};
that.push=function(value){
values.push(value);};return that;};
Check that it works:
......
Total 6 tests (Passed: 6; Fails: 0; Errors: 0) (0.00 ms)
Chrome 16.0.912.75 Mac OS: Run 6 tests (Passed: 6; Fails: 0; Errors 0) (0.00 ms)
Do these tests seem familiar? They are almost straight out ofsrc-test/rpn_calculator_test.js. Along those lines, here's a check similar to the last one we wrote on rpn_calculator:
Run the tests, you'll notice you the result is undefined instead of 0. This is a quick fix:
var rpn_stack =function(){
that ={};var values =[];
that.pop=function(){if(values.length>0)return values.pop();return0;};
that.push=function(value){
values.push(value);};return that;};
Run the tests, you should be back to passing.
A quick check of rpn_calculator.js and you'll notice that while there's a use of ".length", this has been pushed into the new rpn_stack class. However, there's also a need to get the top without removing it. So two more TDD cycles:
Notice that there's some duplication between top and pop. When I know JavaScript well enough, I'll remove it. Until then, let's use this new object in rpn_calculator.
Using rpn_stack in rpn_calculator
Make a few updates to the rpn_calculator class:
var rpn_calculator =function(){var that ={};var values = rpn_stack();
that.value= values;
that.x=function(){return values.top();};
that.enter=function(newValue){
values.push(newValue);};
that.drop=function(){
values.pop()};return that;};
Run the tests, everything should be passing. Here's the full version of rpn_stack.js:
src/rpn_stack.js
var rpn_stack =function(){
that ={};var values =[];
that.pop=function(){if(values.length>0)return values.pop();return0;}
that.push=function(value){
values.push(value);};
that.top=function(){if(values.length>0)return values[values.length-1];return0;};return that;};
Overview
I'm learning JavaScript (again, and for real this time, I hope). After reading JavaScript: The Good Parts and several online pages, I set out to try some basic TDD in JavaScript. For these instructions (and the soon to be created instructional video), I'm using the following tool set:This is my first stab at this and I hope to both get a better workflow and better at JavaScript.
Getting Setup
Setup JsTestDriver. Instructions summarized here for convenience.jsTestDriver.conf
First Test: Initial X Value is 0
src-test/rpn_calculator_test.js
% java -jar JsTestDriver-1.3.3d.jar --tests all java.lang.IllegalArgumentException: The patterns/paths /Users/Thoughtworks/src /workspaces/ RpnCalcDemo/src (/Users/Thoughtworks/src/workspaces/RpnCalcDemo/ src) used in the configuration file didn't match any file, the files patterns/ paths need to be relative /Users/Thoughtworks/src/workspaces/RpnCalcDemo at com.google.jstestdriver.PathResolver.expandGlob(PathResolver.java:170) at com.google.jstestdriver.PathResolver.resolve(PathResolver.java:109) at com.google.jstestdriver.config.ParsedConfiguration.resolvePaths( ParsedConfiguration.java:98) at com.google.jstestdriver.config.Initializer.initialize(Initializer.java:84) at com.google.jstestdriver.JsTestDriver.runConfigurationWithFlags( JsTestDriver.java:259) at com.google.jstestdriver.JsTestDriver.runConfiguration( JsTestDriver.java:211) at com.google.jstestdriver.JsTestDriver.main(JsTestDriver.java:144) Unexpected Runner Condition: The patterns/paths /Users/Thoughtworks/src/ workspaces/RpnCalcDemo/src (/Users/Thoughtworks/src/workspaces/RpnCalcDemo/src) used in the configuration file didn't match any file, the files patterns/ paths need to be relative /Users/Thoughtworks/src/workspaces/RpnCalcDemo Use --runnerMode DEBUG for more information.src/rpn_calculator.js
Next Test: Last Value Entered is X
append to src-test/rpn_calculator_test.js
% java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs .E Total 2 tests (Passed: 1; Fails: 0; Errors: 1) (0.00 ms) Chrome 16.0.912.75 Mac OS: Run 2 tests (Passed: 1; Fails: 0; Errors 1) (0.00 ms) rpn_calculator.testXShouldBeLastValueEntered error (0.00 ms): TypeError: Object #<Object> has no method 'enter' TypeError: Object #<Object> has no method 'enter' at [object Object].testXShouldBeLastValueEntered (http://localhost:9876/test /src-test/rpn_calculator_test.js:10:7) Tests failed: Tests failed. See log for details.src/rpn_calculator.js
Can Handle Multiple Numbers Entered
Appended to src-test/rpn_calculator_test.js
% java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs ..E Total 3 tests (Passed: 2; Fails: 0; Errors: 1) (0.00 ms) Chrome 16.0.912.75 Mac OS: Run 3 tests (Passed: 2; Fails: 0; Errors 1) (0.00 ms) rpn_calculator.testStoresMultipleValues error (0.00 ms): TypeError: Object #<Object> has no method 'drop' TypeError: Object #<Object> has no method 'drop' at Object.testStoresMultipleValues (http://localhost:9876/test/src-test/ rpn_calculator_test.js:23:11) Tests failed: Tests failed. See log for details.src/rpn_calculator.js
One More Check
java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs ...F Total 4 tests (Passed: 3; Fails: 1; Errors: 0) (1.00 ms) Chrome 16.0.912.75 Mac OS: Run 4 tests (Passed: 3; Fails: 1; Errors 0) (1.00 ms) rpn_calculator.testCalculatorAlwaysHasValues failed (0.00 ms): AssertError: expected 0 but was [undefined] AssertError: expected 0 but was [undefined] at Object.testCalculatorAlwaysHasValues (http://localhost:9876/test/src-test/ rpn_calculator_test.js:30:2)Update x method
rpn_stack
rpn_stack_test.js
% java -jar JsTestDriver-1.3.3d.jar --tests all --testOutput logs ....E Total 5 tests (Passed: 4; Fails: 0; Errors: 1) (1.00 ms) Chrome 16.0.912.75 Mac OS: Run 5 tests (Passed: 4; Fails: 0; Errors 1) (1.00 ms) rpn_stack.testPopOnNewStackReturns0 error (1.00 ms): ReferenceError: rpn_stack is not defined ReferenceError: rpn_stack is not defined at [object Object].testPopOnNewStackReturns0 (http://localhost:9876/test/ src-test/rpn_stack_test.js:4:18)Append new test to rpn_stack_test.js
Using rpn_stack in rpn_calculator
src/rpn_stack.js